package com.mervin.helper;

import com.mervin.annotation.LineFieldAnnotation;
import com.mervin.convert.Convert;
import com.mervin.enums.FieldTypeConvertEnum;
import com.mervin.util.ReflectUtil;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/***************************************
 * @author: mervin
 * @Date: 2020-05-04 13:09
 * @Description:
 ***************************************/
public abstract class ParseProcess {

    public Object process(String line, Class<?> clazz) throws IllegalAccessException, InstantiationException, IntrospectionException, InvocationTargetException{
        Object obj = clazz.newInstance();
        List<Field> allDeclaredFieldList = ReflectUtil.getAllDeclaredFields(clazz);

        for(Field field : allDeclaredFieldList) {
            field.setAccessible(true);
            if(!checkField(field)){
                continue;
            }
            String strVal = getFieldStrVal(field, line);
            Object value = convertType(field, strVal);
            fillValue(field, clazz, value, obj);
        }
        return obj;
    }

    /**
     * 获取字段的值，由子类去实现
     * @return
     */
    protected abstract String getFieldStrVal(Field field, String line);

    /**
     * 为属性赋值
     * @param field
     * @param clazz
     * @param value
     * @param obj
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void fillValue(Field field, Class<?> clazz, Object value, Object obj) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clazz);
        // 获得属性的Set方法
        Method method = propertyDescriptor.getWriteMethod();
        // 执行属性的Set方法
        method.invoke(obj, value);
    }

    /**
     * 根据属性字段类型，将字符串值转成属性类型
     * @param field
     * @param strVal
     * @return
     */
    private Object convertType(Field field, String strVal){
        String typeString = field.getGenericType().toString();
        Convert convert = FieldTypeConvertEnum.getConvert(typeString);
        if(convert == null){
            return "";
        }
        return convert.convert(strVal);
    }

    /**
     * 校验字段是否包含指定注解
     * @param field
     * @return
     */
    private boolean checkField(Field field){
        return ReflectUtil.isAnnotationPresent(field, LineFieldAnnotation.class);
    }

}
